/*
  Copyright (c) 2014-2015 NicoHood
  See the readme for credit to other people.

  Gamepad example
  Press a button and demonstrate Gamepad actions

  You can also use Gamepad1,2,3 and 4 as single report.
  This will use 1 endpoint for each gamepad.

  See HID Project documentation for more infos
  https://github.com/NicoHood/HID/wiki/Gamepad-API
*/


#include <Arduino.h>
#include "HID-Project.h"
#include "eepromutil.h"
//https://github.com/NicoHood/HID

void PrintHex(unsigned char *str,unsigned int len);

/*
 *                    S1(D14)   S2(D15)  
 *       A0                                                       /
 *                    5(D2)   6(D4)   7(D6)   8(D8)              /    C1(D10) 
 *   A3       A1                                                / 
 *                    1(D3)   2(D5)   3(D7)   4(D9)            /    RESET
 *       A2                                                   /
 *                                                           /
 */
//const char gameBtns[12] = {10,5,7,9,11,4,6,8,A1,A2,A3,A4};   //初始值按键值


////初始化按键功能
//typedef struct BtnObj_ST {
//  char rBtn[12];
//  byte tBtn[12];
//  char flogBtn[2];
//  char vBtn[12];
//  char repeatDelaytime; //重复按下的延时时间
//}BtnObj;


//
//char realeBtn[12] = {10,5,7,9,11,4,6,8,A1,A2,A3,A4};  //真实12按键和按键顺序对应值
//char btnTypes[12] = {0};                              //12按键功能类型,0:gamepad按键,1:左右摇杆切换功能按键或者摇杆模拟鼠标按键,2:摇杆方向功能键,3:普通电脑键盘,4:鼠标方向按键,5:组合必杀按键或自定义程序值
//
//unsigned char btnRepeatFlog[2] = {0};                       //按键是否为按下后自动重复按压,按位操作,如果相应位为1表示是自动重复按下,0表示没有自动重复按下

//12按键对应值,
//当相应btnTypes为0时,值对应1~32个支持的按键值,
//当相应btnTypes为1时,值为1时表示此键功能为左右摇杆切换,值为2时表示摇杆模拟电脑鼠标,值为3时表示摇杆模拟电脑方向键,值为4时表示摇杆模拟电脑WSAD四个按键
//当相应btnTypes为2时,值对应摇杆的方向值,x正向值为1,x向方向时值为2,y正方向时值为3,y负方向时值为4
//当相应btnTypes为3时,值对应电脑ASCII码按键值
//当相应btnTypes为4时,值为模拟电脑鼠标的相对移动值
//当相应btnTypes为5时,值为组合必杀定义功能选择值,组合必杀功能需要先定义和设置后才可以使用,此功能也可以简单理解为编程值
//char btnVal[12] = {0};                                
//
//char repeatDelayTime = 50;    //

#define PAD_VAL = 32765

//正弦函数1~45度查表值,边长为32765取整
const int16_t dat_sin[46] = {0,571,1143,1714,2285,2855,3424,3993,4560,5125,5689,6251,6812,7370,7926,8480,9031,9579,10124,10667,11206,11741,12274,12802,13326,13847,14363,14875,15382,15884,16382,16875,17362,17845,18321,18793,19258,19718,20172,20619,21060,21495,21924,22345,22760,23168};

//余弦函数1~45度查表值,边长为32765取整
const int16_t dat_cos[46] = {32765,32760,32745,32720,32685,32640,32585,32520,32446,32361,32267,32163,32049,31925,31791,31648,31495,31333,31161,30979,30789,30588,30379,30160,29932,29695,29448,29193,28929,28656,28375,28085,27786,27479,27163,26839,26507,26167,25819,25463,25099,24728,24349,23962,23569,23168};


//const float sqrtab[200] PROGMEM = {0.0000,1.0000,1.4142,1.7321,2.0000,2.2361,2.4495,2.6458,2.8284,3.0000,3.1623,3.3166,3.4641,3.6056,3.7417,3.8730,4.0000,4.1231,4.2426,4.3589,4.4721,4.5826,4.6904,4.7958,4.8990,5.0000,5.0990,5.1962,5.2915,5.3852,5.4772,5.5678,5.6569,5.7446,5.8310,5.9161,6.0000,6.0828,6.1644,6.2450,6.3246,6.4031,6.4807,6.5574,6.6332,6.7082,6.7823,6.8557,6.9282,7.0000,7.0711,7.1414,7.2111,7.2801,7.3485,7.4162,7.4833,7.5498,7.6158,7.6811,7.7460,7.8102,7.8740,7.9373,8.0000,8.0623,8.1240,8.1854,8.2462,8.3066,8.3666,8.4261,8.4853,8.5440,8.6023,8.6603,8.7178,8.7750,8.8318,8.8882,8.9443,9.0000,9.0554,9.1104,9.1652,9.2195,9.2736,9.3274,9.3808,9.4340,9.4868,9.5394,9.5917,9.6437,9.6954,9.7468,9.7980,9.8489,9.8995,9.9499,10.0000,10.0499,10.0995,10.1489,10.1980,10.2470,10.2956,10.3441,10.3923,10.4403,10.4881,10.5357,10.5830,10.6301,10.6771,10.7238,10.7703,10.8167,10.8628,10.9087,10.9545,11.0000,11.0454,11.0905,11.1355,11.1803,11.2250,11.2694,11.3137,11.3578,11.4018,11.4455,11.4891,11.5326,11.5758,11.6190,11.6619,11.7047,11.7473,11.7898,11.8322,11.8743,11.9164,11.9583,12.0000,12.0416,12.0830,12.1244,12.1655,12.2066,12.2474,12.2882,12.3288,12.3693,12.4097,12.4499,12.4900,12.5300,12.5698,12.6095,12.6491,12.6886,12.7279,12.7671,12.8062,12.8452,12.8841,12.9228,12.9615,13.0000,13.0384,13.0767,13.1149,13.1529,13.1909,13.2288,13.2665,13.3041,13.3417,13.3791,13.4164,13.4536,13.4907,13.5277,13.5647,13.6015,13.6382,13.6748,13.7113,13.7477,13.7840,13.8203,13.8564,13.8924,13.9284,13.9642,14.0000,14.0357,14.0712,14.1067};
//小数计算太耗时间了,简化成下边的字节计算
const unsigned char sqrtab[200] PROGMEM = {0,10,14,17,20,22,24,26,28,30,31,33,34,36,37,38,40,41,42,43,44,45,46,47,48,50,50,51,52,53,54,55,56,57,58,59,60,60,61,62,63,64,64,65,66,67,67,68,69,70,70,71,72,72,73,74,74,75,76,76,77,78,78,79,80,80,81,81,82,83,83,84,84,85,86,86,87,87,88,88,89,90,90,91,91,92,92,93,93,94,94,95,95,96,96,97,97,98,98,99,100,100,100,101,101,102,102,103,103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,110,111,111,112,112,113,113,114,114,114,115,115,116,116,117,117,117,118,118,119,119,120,120,120,121,121,122,122,122,123,123,124,124,124,125,125,126,126,126,127,127,128,128,128,129,129,130,130,130,131,131,131,132,132,133,133,133,134,134,134,135,135,136,136,136,137,137,137,138,138,138,139,139,140,140,140,141};


#define PAD_X_ -32760
#define PAD_X  32760
#define PAD_Y 32760
#define PAD_Y_ -32760
#define MIDE_XY 0


extern char rBtn[];
extern char tBtn[];
extern char vBtn[];
extern uint16_t flogBtn;
extern char repeatDelaytime; //重复按下的延时时间
extern char xyFlog;   //bit0:y轴是否反向,bit1:x轴是否反向

extern char isInit;                //是否已设置过值
extern unsigned char adc_max[8];   //摇杆检测到的最大值
extern unsigned char adc_min[8];   //摇杆检测到的最小值



bool isRightYG = false;

extern unsigned char adc_buffer[];   //摇杆数据

char citieType = 0;          //1:磁铁为离的近时值越大,2:反之为离的越近值越小,0:未初始化
bool isADCInit_MM = true;   //ADC最大值和最小值是是否初始化完成

unsigned char adc_val[8] = {0}; //摇杆最大值和最小值之间的最大差值





void initGamgPadADC()
{
      initEEPROM();
      if( isInit){
          for(int i=0;i<8;i++)
          {
            unsigned char dottmp =  adc_max[i] -  adc_min[i];
            if( adc_min[i] == 0 ||   adc_max[i] == 0 || (dottmp < 0x30)){
              isADCInit_MM = false;
            }
          }
       }else{
          for(int i=0;i<8;i++)
          {
             adc_max[i] = 0 ;
             adc_min[i] = 0xff;
          }
          isADCInit_MM = false;
       }
}

void gamePadInit() 
{
  initGamgPadADC();
  delay(10);
  for(int i = 0;i<12;i++){
    pinMode(rBtn[i], INPUT_PULLUP);
  }
  // Sends a clean report to the host. This is important on any Arduino type.
  Gamepad.begin();
}


void updateADCDot()
{
    bool isTmp = true;
     for(int i=0;i<8;i++)
     {
        unsigned char dottmp =  adc_max[i] -  adc_min[i];
        if( adc_min[i] == 0 ||   adc_max[i] == 0 || (dottmp < 0x30)){
          isTmp = false;
        }
     }
     isADCInit_MM = isTmp;
     if(isTmp)
     {
         isInit = true;
        saveADCObj();
     }
     
}

int adc_id1 = -1;
int adc_id2 = -1;
unsigned char adc_v1 = 0;           //最大值1
unsigned char adc_v2 = 0;           //最大值2
unsigned char adc_vnear = 0;        //最大值第三个相关值
unsigned char adc_vmin = 0xff;      //adc的最小值



bool testADCMaxAndMin()
{
  if(isADCInit_MM)
   {
        
        bool isChange = false;
        adc_v1 = 0;
        adc_vmin = 0xef;
        for(int i=0;i<8;i++)
        {
          if( adc_max[i] < adc_buffer[i]){
             adc_max[i] = adc_buffer[i];
            isChange = true;
          }
          if( adc_min[i] == 0 ||  adc_min[i] > adc_buffer[i]){
             adc_min[i] = adc_buffer[i];
            isChange = true;
          }
          
          if(citieType == 1){
              adc_val[i] = adc_buffer[i] -  adc_min[i];
            }else if(citieType == 2){
              adc_val[i] =  adc_max[i] - adc_buffer[i];
            }
          if(adc_v1 < adc_val[i]){
             adc_id1 = i;
             adc_v1 = adc_val[i];
          }
          if(adc_vmin > adc_val[i]){
            adc_vmin = adc_val[i];
          }
        }
//        PrintHex(adc_buffer,8);
//        PrintHex(adc_val,8);
//        Serial.println(adc_v1,HEX);
//          Serial.println(adc_id1,HEX);
//        PrintHex(m_adcobj.adc_max,8);
//          PrintHex(m_adcobj.adc_min,8);
        if(isChange){
          saveADCObj();
        }
        return true;
    }else{
        bool isChange = false;
        for(int i=0;i<8;i++)
        {
          if(adc_max[i] < adc_buffer[i]){
            adc_max[i] = adc_buffer[i];
            isChange = true;
          }
          if( adc_min[i] == 0 ||  adc_min[i] > adc_buffer[i]){
             adc_min[i] = adc_buffer[i];
            isChange = true;
          }
        }
        if(isChange){
          updateADCDot();
        }
    }
    return false;
}

//摇杆所在象限查表,id1,id2确定一个查表值
/******
 *            0
 *            y
 *      1     ^     7
 *       \    |    /
 *        \ 3 | 2 /
 *       4 \  |  / 1
 *  2 --------+------>x  6
 *       5 /  |  \ 8
 *        / 6 | 7 \
 *       /    |    \
 *      3     4     5
 * 0,7=   2  //v2小角度,先x=sin,y=cos  ,x>0,y>0
 *                0           1         1   1     =0x07 
 * 0,1=   3  //v2小角度,先x=sin,y=cos  ,x<0,y>0
 *                0           1         0   1     =0x05
 * 1,0=   3  //v1大角度,先x=sin,y=cos  ,x<0,y>0
 *                1           1         0   1     =0x0d
 * 1,2=   4  //v1大角度,先x=cos,y=sin  ,x<0,y>0
 *                1           0         0   1     =0x09
 * 2,1=   4  //v2小角度,先x=cos,y=sin  ,x<0,y>0
 *                0           0         0   1     =0x01
 * 2,3=   5  //v2小角度,先x=cos,y=sin  ,x<0,y<0
 *                0           0         0   0     =0x00
 * 3,2=   5  //v1大角度,先x=cos,y=sin  ,x<0,y<0
 *                1           0         0   0     =0x08
 * 3,4=   6  //v1大角度,先x=sin,y=cos  ,x<0,y<0
 *                1           1         0   0     =0x0c
 * 4,3=   6  //v2小角度,先x=sin,y=cos  ,x<0,y<0
 *                0           1         0   0     =0x04
 * 4,5=   7  //v2小角度,先x=sin,y=cos  ,x>0,y<0
 *                0           1         1   0     =0x06
 * 5,4=   7  //v1大角度,先x=sin,y=cos  ,x>0,y<0
 *                1           1         1   0     =0x0e
 * 5,6=   8  //v1大角度,先x=cos,y=sin  ,x>0,y<0
 *                1           0         1   0     =0x0a
 * 6,5=   8  //v2小角度,先x=cos,y=sin  ,x>0,y<0
 *                0           0         1   0     =0x02
 * 6,7=   1  //v2小角度,先x=cos,y=sin  ,x>0,y>0
 *                0           0         1   1     =0x03
 * 7,6=   1  //v1大角度,先x=cos,y=sin  ,x>0,y>0
 *                1           0         1   1     =0x0b
 * 7,0=   2  //v1大角度,先x=sin,y=cos  ,x>0,y>0
 *                1           1         1   1     =0x0f  
 * 定义0x00的低4位为标志位,则
 * bit4,第4位为1使用大角度v1,为0使用小角度v2计算sin和cos
 * bit3,1:x=sin,y=cos;0:x=cos,y=sin
 * bit2,1:x>0,0:x<0
 * bit1,1:y>0,0:y<0
 */
//const char adc_states[8][8] = {0};   
char getFlogVale(unsigned char a,unsigned char b)
{
  char tmp = 0x00;
  switch(a){
    case 0:
    {
        if(b == 1){//0,1
          tmp = 0x05;
        }else{//0,7
          tmp = 0x07;
        }
    }
    break;
    case 1:
    {
        if(b == 0){//1,0
          tmp = 0x0d;
        }else{//1,2
          tmp = 0x09;
        }
    }
    break;
    case 2:
    {
        if(b == 1){//2,1
          tmp = 0x01;
        }else{//2,3
          tmp = 0x00;
        }
    }
    break;
    case 3:
    {
        if(b == 2){//3,2
          tmp = 0x08;
        }else{//3,4
          tmp = 0x0c;
        }
    }
    break;
    case 4:
    {
        if(b == 3){//4,3
          tmp = 0x04;
        }else{//4,5
          tmp = 0x06;
        }
    }
    break;
    case 5:
    {
        if(b == 4){//5,4
          tmp = 0x0e;
        }else{//5,6
          tmp = 0x0a;
        }
    }
    break;
    case 6:
    {
        if(b == 5){//6,5
          tmp = 0x02;
        }else{//6,7
          tmp = 0x03;
        }
    }
    break;
    case 7:
    {
        if(b == 0){//7,0
          tmp = 0x0f;
        }else{//7,6
          tmp = 0x0b;
        }
    }
    break;
  }
  
    tmp ^=  xyFlog;
    
  return tmp;
}



void getNearID()
{
  if(adc_id1 == 0)
  {
      if(adc_val[7] > adc_val[1])
      {
        adc_id2 = 7;
        adc_vnear = adc_val[1];
      }else{
        adc_id2 = 1;
        adc_vnear = adc_val[7];
      }
  }else if(adc_id1 == 7){
      if(adc_val[6] > adc_val[0])
      {
        adc_id2 = 6;
        adc_vnear = adc_val[0];
      }else{
        adc_id2 = 0;
        adc_vnear = adc_val[6];
      }

  }else{
      if(adc_val[adc_id1-1] > adc_val[adc_id1+1])
      {
        adc_id2 = adc_id1-1;
        adc_vnear = adc_val[adc_id1+1];
      }else{
        adc_id2 = adc_id1+1;
        adc_vnear = adc_val[adc_id1-1];
      }
  }
}

////消除最小值
void reserData()
{
  for(char i=0;i<8;i++){
    adc_val[i] -= adc_vmin;
  }
}

int16_t jiaodu_s = -1;     //当前发送角度
int16_t padx_s = 0;       //x方向发送值
int16_t pady_s = 0;       //y方向发送值

int16_t jiaodu_n = -1;   //角度预估下次值
int16_t padx_n = 0;     //x方向值预估下次值
int16_t pady_n = 0;     //y方向值预估下次值

int16_t jiaodu = -1;   //角度实际真实值
int16_t padx = 0;     //x方向值实际真实值
int16_t pady = 0;     //y方向值实际真实值

//这里主要为了消除摇杆转到时出现的角度抖动,使用方法如下:
/*
 * ---1----2----3----4----5-----假设的摇杆转动角度
 *              ^    ^   ^
 *              当   预   实
 *              前   计   际
 *              发   方   真
 *              送   向   实
 *              值   值   值
 * 
 * 当前发送值:当前发送给USB的摇杆值,由预计发送值得到
 * 预计发送值:当前摇杆刚刚经过的当前发送值偏差值,由真实值过当送值临近值时得到
 * 实际真实值:当实际真实值和预计值相差1,和发送值差2时,真实值变更为预计值,预计值变更为发送值,并把发送值送到USB提到摇杆真实转动效果
 */
 
//通过传感器方向状态和简单相对角度值计算当前实际角度,并检测是否要更新发送值和预测值
//v,传感器方向状态标志数据,a,传感器数值得到的相对角度值
//摇杆所在象限查表,id1,id2确定一个查表值
/******
 *            0
 *            y
 *      1     ^     7
 *       \    |    /
 *        \ 3 | 2 /
 *       4 \  |  / 1
 *  2 --------+------>x  6
 *       5 /  |  \ 8
 *        / 6 | 7 \
 *       /    |    \
 *      3     4     5
 */
void countNowAngle(char v,char a)
{
  char tv = v ^ ( xyFlog);//去掉设置的坐标反转
  switch(v){
    case 0x00://2,3=   5  v2小角度   先x=cos,y=sin  ,x<0,y<0
    {
      jiaodu = 180 + a;
    }
    break;
    case 0x01://2,1=   4  v2小角度   先x=cos,y=sin  ,x<0,y>0
    {
      jiaodu = 180 - a;
    }
    break;
    case 0x02://6,5=   8  v2小角度   先x=cos,y=sin  ,x>0,y<0
    {
      jiaodu = 360 - a;
    }
    break;
    case 0x03://6,7=   1  v2小角度   先x=cos,y=sin  ,x>0,y>0
    {
      jiaodu = a;
    }
    break;
    case 0x04://4,3=   6  v2小角度   先x=sin,y=cos  ,x<0,y<0
    {
      jiaodu = 270 - a;
    }
    break;
    case 0x05://0,1=   3  v2小角度   先x=sin,y=cos  ,x<0,y>0
    {
      jiaodu = 90 + a;
    }
    break;
    case 0x06://4,5=   7  v2小角度   先x=sin,y=cos  ,x>0,y<0
    {
      jiaodu = 270 + a;
    }
    break;
    case 0x07://0,7=   2  v2小角度   先x=sin,y=cos  ,x>0,y>0
    {
      jiaodu = 90 - a;
    }
    break;
    case 0x08://3,2=   5  v1大角度   先x=cos,y=sin  ,x<0,y<0
    {
      jiaodu = 180 + a;
    }
    break;
    case 0x09://1,2=   4  v1大角度   先x=cos,y=sin  ,x<0,y>0
    {
      jiaodu = 180 - a;
    }
    break;
    case 0x0a://5,6=   8  v1大角度   先x=cos,y=sin  ,x>0,y<0
    {
      jiaodu = 360 - a;
    }
    break;
    case 0x0b://7,6=   1  v1大角度   先x=cos,y=sin  ,x>0,y>0
    {
      jiaodu = a;
    }
    break;
    case 0x0c://3,4=   6  v1大角度   先x=sin,y=cos  ,x<0,y<0
    {
      jiaodu = 270 - a;
    }
    break;
    case 0x0d://1,0=   3  v1大角度   先x=sin,y=cos  ,x<0,y>0
    {
      jiaodu = 90 + a;
    }
    break;
    case 0x0e://5,4=   7  v1大角度   先x=sin,y=cos  ,x>0,y<0
    {
      jiaodu = 270 + a;
    }
    break;
    case 0x0f://7,0=   2  v1大角度   先x=sin,y=cos  ,x>0,y>0
    {
      jiaodu = 90 - a;
    }
    break;
  }
  
  if(jiaodu_n == -1){
    jiaodu_n = jiaodu;
    jiaodu_s = jiaodu;
    padx_s = padx;
    pady_s = pady;
    padx_n = padx;
    pady_n = pady;
  }else if(abs(jiaodu_n - jiaodu_s) >= 1 ){
    char tmpdot = abs(jiaodu_n - jiaodu_s);
    if(abs(jiaodu - jiaodu_s) > tmpdot){
      jiaodu_s = jiaodu_n;
      jiaodu_n = jiaodu;
      padx_n = padx;
      pady_n = pady;
      padx_s = padx_n;
      pady_s = pady_n;
    }else{
      jiaodu_n = jiaodu;
      padx_n = padx;
      pady_n = pady;
    }
  }else{
    jiaodu_n = jiaodu;
      padx_n = padx;
      pady_n = pady;
  }
}

void conventAngle()
{
//  Serial.println(adc_v1);
  if(adc_v1 >= 0x10){ //说明摇杆已经摇动
    getNearID();
    char tmpAngle = 0;
    char tmpv = getFlogVale(adc_id1,adc_id2);
    unsigned char v1sqr;
    unsigned char v2sqr;
      adc_v1 = adc_val[adc_id1] - adc_vnear;
      adc_v2 = adc_val[adc_id2] - adc_vnear;
      
      
      v1sqr = pgm_read_byte(&sqrtab[adc_v1]);
      v2sqr = pgm_read_byte(&sqrtab[adc_v2]);
      if(tmpv & 0x08){//大角度
        tmpAngle = v1sqr*45.0/(v1sqr+v2sqr);
      }else{//小角度
        tmpAngle = v2sqr*45.0/(v1sqr+v2sqr);
      }
    if(tmpv & 0x04){//x=sin,y=cos
      padx = dat_sin[tmpAngle];
      pady = dat_cos[tmpAngle];
    }else{//x=cos,y=sin
      pady = dat_sin[tmpAngle];
      padx = dat_cos[tmpAngle];
    }
    if(!(tmpv & 0x02)){//x值小于0
      padx = -padx;
    }
    if(!(tmpv & 0x01)){//y值小于0
      pady = -pady;
    }

#if 1   //是否使用消抖函数,1不使用摇杆抖动消除算法,0使用摇杆消除抖动算法
    padx_s = padx;
    pady_s = pady;
#else
    countNowAngle(tmpv,tmpAngle);
#endif

  }else{//摇杆没有动作,清除摇杆数据
    jiaodu = -1;
    jiaodu_n = -1;
    jiaodu_s = -1;
    pady_s = 0;
    padx_s = 0;
  }
  
}

//更新摇杆角度
bool updateAngle()
{
  switch(citieType)
  {
    case 0://磁铁方向未初始化
    {
      for(int i=0;i<8;i++)
      {
        if(adc_buffer[i] > 0xB0){
          citieType = 1;
        }else if(adc_buffer[i] < 0x50){
          citieType = 2;
        }
      }
    }
    break;
    case 1://已初始化磁铁为值变大
    {
      if(testADCMaxAndMin()){
        conventAngle();
        return true;
      }
      
    }
    break;
    case 2://已初始化磁铁为值变小
    {
      if(testADCMaxAndMin()){
        conventAngle();
        return true;
      }
      
    }
    break;
  }
  return false;
}

char gamepadType = 0;     //0:摇杆为左摇杆,1:摇杆为右摇杆,2:摇杆为电脑鼠标,3:摇杆为电脑方向键,4,摇杆为电脑WSAD键盘4键,5,摇杆为手柄上的4方向按键
uint16_t btnTouchType = 0;  //按键是否按下过的标志
void updateGamePad() {
    if(!updateAngle()){
      return;
    }
//    PrintHex( rBtn,12);
    for(char i = 0;i<12;i++)
    {
//      char realeBtn[12] = {10,5,7,9,11,4,6,8,A1,A2,A3,A4};  //真实12按键和按键顺序对应值

      if(!digitalRead(rBtn[i]))
      {
        
        switch(tBtn[i])
        {
          case 0://gamepad正常按键
          {
            if(flogBtn & (1<<i)){//标志位持续重复按下
                if(btnTouchType & (1<<i)){
                  Gamepad.press(vBtn[i]);
                  btnTouchType |= (1<<i); 
                }else{
                  Gamepad.press(vBtn[i]);
                  btnTouchType &= (~(1<<i));
                }
              }else{
                Serial.println(vBtn[i],HEX);
                Gamepad.press(vBtn[i]);
              }
          }
          break;
          case 1://左右摇杆切换功能按键或者摇杆模拟鼠标按键
          {
            if(vBtn[i] == 1)//表示此键功能为左右摇杆切换
            {
              gamepadType = 1;//切换摇杆为右摇杆
            }else if(vBtn[i] == 2){//表示摇杆模拟电脑鼠标
              gamepadType = 2;//  
            }else if(vBtn[i] == 3){//表示摇杆模拟电脑方向键
              if(flogBtn & (1<<i)){//标志位持续重复按下
                if(gamepadType == 3){
                  gamepadType = 0;// 
                }else{
                  gamepadType = 3;
                }
                delay(300);
              }else{
                gamepadType = 3;
              }
              
            }else if(vBtn[i] == 4){//表示摇杆模拟电脑WSAD四个按键
              if(flogBtn & (1<<i)){//标志位持续重复按下
                if(gamepadType == 4){
                  gamepadType = 0;// 
                }else{
                  gamepadType = 4;
                }
                delay(300);
              }else{
                gamepadType = 4;
              }
            }else if(vBtn[i] == 5){//5,摇杆为手柄上的4方向按键
               if(gamepadType == 5){
                  gamepadType = 0;// 
                }else{
                  gamepadType = 5;
                }
                delay(300);
            }else{//其他可能,未定义
              gamepadType = 0;
            }
          }
          break;
          case 2://摇杆方向功能键
          {
            
          }
          break;
          case 3://普通电脑键盘
          {
            
          }
          break;
          case 4://鼠标方向按键
          {
            
          }
          break;
          case 5://组合必杀按键或自定义程序值
          {
            
          }
          break;
        }
        
      }else{
        
        switch(tBtn[i])
        {
          case 0://gamepad正常按键
          {
            Gamepad.release(vBtn[i]);
          }
          break;
          case 1://左右摇杆切换功能按键或者摇杆模拟鼠标按键
          {
            if(vBtn[i] == 1)//表示此键功能为左右摇杆切换
            {
              gamepadType = 0;//切换回左摇杆
            }else if(vBtn[i] == 2){//表示摇杆模拟电脑鼠标
              gamepadType = 0;//切换回左摇杆
            }else if(vBtn[i] == 3){//表示摇杆模拟电脑方向键
              if(!(flogBtn & (1<<i))){//标志位持续重复按下
                gamepadType = 0;//切换回左摇杆
              }
            }else if(vBtn[i] == 4){//表示摇杆模拟电脑WSAD四个按键
              if(!(flogBtn & (1<<i))){//标志位持续重复按下
                gamepadType = 0;//切换回左摇杆
              }
            }else{//其他可能,未定义
              gamepadType = 0;//切换回左摇杆
            }
          }
          break;
          case 2://摇杆方向功能键
          {
            
          }
          break;
          case 3://普通电脑键盘
          {
            
          }
          break;
          case 4://鼠标方向按键
          {
            
          }
          break;
          case 5://组合必杀按键或自定义程序值
          {
            
          }
          break;
        }
        
      }
    }

//0:摇杆为左摇杆,1:摇杆为右摇杆,2:摇杆为电脑鼠标,3:摇杆为电脑方向键,4,摇杆为电脑WSAD键盘4键,5,摇杆为手柄上的4方向按键
    switch(gamepadType){
      case 0://0:摇杆为左摇杆
      {
        Gamepad.xAxis(padx_s);
        Gamepad.yAxis(pady_s);
      }
      break;
      case 1://1:摇杆为右摇杆
      {
        Gamepad.rxAxis(padx_s);
        Gamepad.ryAxis(pady_s);
      }
      break;
      case 2://2:摇杆为电脑鼠标
      {
        
      }
      break;
      case 3://3:摇杆为电脑方向键
      {
        
      }
      break;
      case 4://4,摇杆为电脑WSAD键盘4键
      {
        
      }
      break;
      case 5://5,摇杆为手柄上的4方向按键
      {
        
      }
      break;
    }

  Gamepad.write();

//  delay(10);
}
